// Copyright 2024 The Google Research Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package streetview_contrails_dataset;

// NB: all timestamp fields are UTC.

message LinearContrail {
  float lat1 = 1;
  float lng1 = 2;
  float lat2 = 3;
  float lng2 = 4;
  uint64 timestamp = 5;

  // Contrails have an altitude, but we deliberately do not track one here.
  //
  // StreetView detections have their altitude inferred from flightmatches,
  // and the lat/lng coordinates here are determined by that altitude.
  // Note flight waypoint altitudes may change over the length of the contrail,
  // so you should process them directly, e.g. decide if taking a mean
  // is acceptable for your use case.
  //
  // Satellite detections do not have an inferred altitude at the moment.
  // Assuming the match of the advected flight waypoints to the detected
  // satellite contrail is correct, the advected altitude
  // of the  flight waypoints is perhaps the most accurate estimate
  // of the contrail's current altitude - but again make a decision
  // that is appropriate for your use case.
}

message FlightMatchScore {
  float score = 1;
  string version = 2;
}

message EcmwfData {
  // Fraction of cloud cover (0, 1)).
  double cc = 1;
  // Cloud ice water content (kg/kg).
  double ciwc = 2;
  // Cloud liquid water content (kg/kg).
  double clwc = 3;
  // Cloud rain water content (kg/kg).
  double crwc = 4;
  // Cloud snow water content (kg/kg).
  double cswc = 5;
  // Windfield divergence.
  double d = 6;
  // Eta coordinate vertical velocity.
  double etadot = 7;
  // Specific humidity (kg/kg)
  double q = 8;
  // Temperature (K)
  double t = 9;
  // U (eastward) component of wind (m/s)
  double u = 10;
  // V (northward) component of wind (m/s)
  double v = 11;
  // Relative vorticity (does NOT include coriolis effect).
  double vo = 12;
  // Vertical velocity (Pa/s).
  double w = 13;
  // Geopotential (m^2/s^2)
  double z = 14;
  // Relative humidity (%)
  double r = 15;
  // Potential vorticity (K*m^2/kg/s)
  double pv = 16;
}

message Location {
  uint64 timestamp = 1;
  float latitude = 2;
  float longitude = 3;

  // Altitude of un-advected flight waypoints (that is, those reported
  // in FormationInfo) are as reported by ADS-B aggregated by FlightAware,
  // and "In general, it is best to assume altitudes are uncorrected pressure
  // altitudes" [https://en.wikipedia.org/wiki/Pressure_altitude].
  // https://flightaware.com/about/faq/#AGLorMSL

  // Altitudes which have undergone advection (that is, those reported in
  // PersistenceLabel) have, during advection, been converted into
  // geopotential height [https://en.wikipedia.org/wiki/Geopotential_height]
  // and after 3D advection have been converted back to geometric meters
  // with the formula "altitude_meters = geo_potential / (9.80665 * 0.98)".
  // [https://glossary.ametsoc.org/wiki/Geopotential_height]
  float altitude_meters = 4;

  EcmwfData era5_data = 5;
}

message Waypoints {
  repeated Location points = 1;
}

message FormationInfo {
  int64 flight_id = 1;
  string aircraft_type = 6;
  Waypoints nearby_flight_waypoints = 5;
  LinearContrail streetview_contrail = 3;
  FlightMatchScore match_score = 4;
  string streetview_detection_id = 7;

  reserved 2;
}

message PlausibleOtherFlight {
  int64 flight_id = 1;
  Waypoints nearby_flight_waypoints = 2;
}


enum DetectionOutcome {
  NOT_DETECTED = 0;
  DETECTED_MULTIPLE_CANDIDATES = 1;
  DETECTED_SINGLETON = 3;
  MISSING_SATELLITE_DATA = 2;
}

message PersistenceLabel {
  // The time of the satellite imagery.
  uint64 timestamp = 1;

  // Whether the contrail was confirmed to persist or not.
  DetectionOutcome detected = 2;

  // Details of the method, e.g. which model and thresholds.
  string detected_by = 3;

  // Only present if `detected` == DetectionOutcome.DETECTED_SINGLETON
  // or `detected` == DetectionOutcome.DETECTED_MULTIPLE_CANDIDATES.
  optional LinearContrail satellite_contrail = 4;

  // Flight waypoints from FormationInfo advected forward
  // in time to the `timestamp` above,
  Waypoints advected_flight_waypoints = 6;

  // If satellite_contrail is present,
  // this contains other flights that plausibly caused it (aside from the
  // Streetview-imaged flight that's recorded in advected_flight_waypoints).
  repeated PlausibleOtherFlight plausible_other_flights = 7;

  reserved 5;
}

message DatasetEntry {
  FormationInfo formation_info = 1;
  repeated PersistenceLabel persistence_labels = 2;
}
